/*
 * Copyright 2020 zytech
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#ifndef _EMBEDDED_RPC__SERVER_TCP_TRANSPORT_H_
#define _EMBEDDED_RPC__SERVER_TCP_TRANSPORT_H_
#include <memory>
#include "erpc_framed_transport.h"
#include "erpc_threading.h"
#include <thread>
#if defined(_MSC_VER) || defined(__MINGW32__)
#define WINSOCK_USED
#define _SOCK_TYPE_ SOCKET
#include <WinSock2.h>
#elif defined(__unix)
//#else
#define _SOCK_TYPE_ int
#endif

/*!
 * @addtogroup tcp_transport
 * @{
 * @file
 */

////////////////////////////////////////////////////////////////////////////////
// Classes
////////////////////////////////////////////////////////////////////////////////

namespace erpc {
/*!
 * @brief Server side of TCP/IP transport.
 *
 * @ingroup tcp_transport
 */
class ServerTCPTransport : public FramedTransport
{
public:
    /*!
     * @brief Constructor.
     *
     * This function initializes object attributes.
     *
     */
    ServerTCPTransport();

    /*!
     * @brief Constructor.
     *
     * This function initializes object attributes.
     *
     * @param[in] host Specify the host name or IP address of the computer.
     * @param[in] port Specify the listening port number.
     */
    ServerTCPTransport(const char *host, uint16_t port);

    /*!
     * @brief ServerTCPTransport destructor
     */
    virtual ~ServerTCPTransport(void);

    /*!
     * @brief This function set host and port of this transport layer.
     *
     * @param[in] host Specify the host name or IP address of the computer.
     * @param[in] port Specify the listening port number.
     */
    void configure(const char *host, uint16_t port);

    /*!
	 * @brief This function set host and port of this transport layer.
	 *
	 * @param[in] sendTimeoutMills Specify timeout(milliseconds) for sending. ignore if less than or equal to zero
	 * @param[in] recvTimeoutMills Specify timeout(milliseconds) for receiving. ignore if less than or equal to zero
	 */
	void timeout(uint32_t sendTimeoutMills,uint32_t recvTimeoutMills);
    /*!
     * @brief This function will create host on server side, or connect client to the server.
     *
     * @retval #kErpcStatus_Success When creating host was successful or client connected successfully.
     * @retval #kErpcStatus_UnknownName Host name resolution failed.
     * @retval #kErpcStatus_ConnectionFailure Connecting to the specified host failed.
     */
    virtual erpc_status_t open(void);

    /*!
     * @brief This function disconnects client or stop server host.
     *
     * @retval #kErpcStatus_Success Always return this.
     */
    virtual erpc_status_t close(void);
    /*!
     * @brief This function disconnects client
     *
     * @retval #kErpcStatus_Success Always return this.
     */
    virtual erpc_status_t closeClientSocket(void);

    virtual std::shared_ptr<void> getReqSocketQueue(void);

	virtual void setSocket(_SOCK_TYPE_ socket);
	virtual _SOCK_TYPE_ getSocket(void);
	static const uint32_t DEFAULT_TIMEOUT_MILLS;
protected:
    const char *m_host;    /*!< Specify the host name or IP address of the computer. */
    uint16_t m_port;       /*!< Specify the listening port number. */
    static thread_local _SOCK_TYPE_ m_socket;   /*!< Socket number. */
    std::shared_ptr<void> m_reqSockets; /*!< Client Request Socket queue. */
    Thread m_serverThread; /*!< Pointer to server thread. */
    bool m_runServer;      /*!< Thread is executed while this is true. */
    uint32_t m_sendTimeoutMills;/*!< send timeout(milliseconds). default 4 seconds */
    uint32_t m_recvTimeoutMills;/*!< receive timeout(milliseconds). default 4 seconds */
    /*!
     * @brief This function read data.
     *
     * @param[inout] data Preallocated buffer for receiving data.
     * @param[in] size Size of data to read.
     *
     * @retval #kErpcStatus_Success When data was read successfully.
     * @retval #kErpcStatus_ReceiveFailed When reading data ends with error.
     * @retval #kErpcStatus_ConnectionClosed Peer closed the connection.
     */
    virtual erpc_status_t underlyingReceive(uint8_t *data, uint32_t size);

    /*!
     * @brief This function writes data.
     *
     * @param[in] data Buffer to send.
     * @param[in] size Size of data to send.
     *
     * @retval #kErpcStatus_Success When data was written successfully.
     * @retval #kErpcStatus_SendFailed When writing data ends with error.
     * @retval #kErpcStatus_ConnectionClosed Peer closed the connection.
     */
    virtual erpc_status_t underlyingSend(const uint8_t *data, uint32_t size);

    /*!
     * @brief Server thread function.
     */
    void serverThread(void);

    /*!
     * @brief Thread entry point.
     *
     * Control is passed to the serverThread() method of the ServerTCPTransport instance pointed to
     * by the @c arg parameter.
     *
     * @param arg Thread argument. The pointer to the ServerTCPTransport instance is passed through
     *  this argument.
     */
    static void serverThreadStub(void *arg);
};

} // namespace erpc

/*! @} */

#endif // _EMBEDDED_RPC__SERVER_TCP_TRANSPORT_H_
